package com.benyi.byiee.filter;

import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import java.util.UUID;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.benyi.byiee.constants.Role;
import com.benyi.byiee.constants.UserType;
import com.benyi.byiee.model.api.User;
import com.benyi.byiee.model.db.UserAccount;
import com.benyi.byiee.util.OnlineUserList;
import com.benyi.byiee.util.RequestContext;
import com.benyi.util.Config;
import com.benyi.util.JsonTool; 

@Component
public class MyInterceptor implements HandlerInterceptor {
	 
	private static Logger log = LoggerFactory.getLogger(MyInterceptor.class);
	
	@Resource(name="config")
	private Config config; 
	
	private long lastCheckTime = 0;
	
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 
        System.out.println("Pre Handle method is Calling");
        removeExpiredUser(); //删除过期的登录 
        
		UUID uuid = UUID.randomUUID();
		String requestId = uuid.toString(); 
		
        RequestContext.setRequestId(requestId);
        RequestContext.setRequest(request);
        RequestContext.setResponse(response);

    	if ( !(handler instanceof HandlerMethod)) {
			return true;
		}
    	/*
    	Enumeration<String> es = request.getHeaderNames();
    	while(es.hasMoreElements()) {
    		String n = es.nextElement();
    		System.out.println(n+"\t"+request.getHeader(n));
    	}
    	System.out.println("--------------------");
    	*/
    	
		HandlerMethod handlerMethod = (HandlerMethod) handler; 
        String methodName = handlerMethod.getMethod().getName(); // 获取方法名 
        String className = handlerMethod.getMethod().getDeclaringClass().getSimpleName();    // 获取类名
        
        String token = request.getHeader("token"); 
        
        log.info("Calling method: " + className + "." + methodName);  
		
		log.debug("进入过滤,requestId:{},from IP:{},url:{},token:{}",requestId,
				  request.getRemoteAddr(),request.getRequestURI(),token); 
        
		Method m = handlerMethod.getMethod();
		boolean pass = checkPermit(m, request);

		if (pass == false) {
			writeNotAuth(response);
			return false;
		}
	 
		return true; // 只有返回true才会继续向下执行，返回false取消当前请求
    }
    
    private boolean checkPermit(Method m, HttpServletRequest request) {
		
    	Annotation[] as = m.getAnnotations();
		if (as == null) {
			return true;
		}
		
		String ip=RequestContext.getRequestIp(); 
		
		String token=request.getHeader("token");
		if(token==null){
			token=request.getParameter("token");
		}
		
		User user = OnlineUserList.getUser(token);  
		
		boolean pass=false; 
		
		Role r = null;
		int roles=0;
		for (int i = 0; i < as.length; i++) {
			if (as[i] instanceof Role) { //方法上可以定义多个 Role
				roles++;  
			}
		}
		
		if (roles == 0) { //没有定义，则pass
			log.debug("no roles defined on this method,pass!");
			return true; 
		}  
		
		if(user == null) {
			log.info("no login user,token:{}",token);
			return false;
		}
		
		log.debug("Intercepter , User:"+JsonTool.toString(user));
		UserAccount ua = user.getAccount();
		
		for (int i = 0; i < as.length; i++) {
			if ( !(as[i] instanceof Role)) { //方法上可以定义多个 Role
				continue;
			} 
			r = (Role) as[i]; 
			if(r.value() == ua.getUtype() || r.value() == UserType.ALL) { //检查用户类型
				if(ip.equalsIgnoreCase(user.getFromIp())==true) {
					pass = true;
				}else { 
					pass = false;
				}  
				break;
			}
		}
		log.info("Check role , token:{},from IP:{},login IP:{},result{}",token,ip,user.getFromIp(),pass);
		
		return pass;
	}

	private void writeNotAuth(HttpServletResponse response) throws IOException {
		log.debug("filter,no right to execute ..., report 401, requestId:{}",RequestContext.getRequestId()); 
		response.setHeader("Content-Type", "text/html;charset=UTF-8");
		response.setStatus(401);
		response.getWriter().write("Not authorised!");  
		response.getWriter().flush(); 
	} 
    
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 在请求处理之后，视图渲染之前执行
        //System.out.println("Post Handle method is Calling");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    	long time = System.currentTimeMillis() - RequestContext.getTime();
    	log.info("process time ,Id:{} ,spent:{}",RequestContext.getRequestId(),time);
        RequestContext.clear(); 
    }
    
    private void removeExpiredUser() {
    	int period = config.getInt("check_period");
    	int time = config.getInt("expire_time");
    	long t = (System.currentTimeMillis() - lastCheckTime)/1000;
    	if(t<period) {
    		return;
    	}
    	lastCheckTime = System.currentTimeMillis();
    	log.info("start check expired user , size:{}" , OnlineUserList.getUserNum());
    	
		HashMap<String,User> list =  OnlineUserList.getUserList();
		Set<String> ks = list.keySet();
		Object []oks = ks.toArray();
		  
		User user;
		
		for(int i=0;i<oks.length;i++) { 
			user = OnlineUserList.getUser((String)oks[i]);
			if(user != null) {
				if(user.isExpired(time)) {
					OnlineUserList.removeUser((String)oks[i]);
					log.info("remove exipred user, token:{},emial:{}" + (String)oks[i] , user.getEmail()); 
				} 
			}
		}
		
		log.info("end of check expired user,user size:{}",OnlineUserList.getUserNum());
	}
}